#pragma once
#include "math_base.h"
#include <omp.h>
typedef struct 
{
	int nInputCount;
	double rO;
	double* pWeights;
}Perceptron;

class MSP
{
public:
	Perceptron* m_pPerceptrons;
	int m_nPerceptronCount;

	double m_rActiveRate;
	int m_nActiveMode;

	double* m_pX;
	double* m_pO;
	int m_nXSize;
	int m_nOSize;

	double* m_pWeights;
	int m_nWeightCount;
	
	bool m_bIsShell;

	MSP(void){};
	MSP(double active_rate, int active_mode,int input_size, int output_size, int perceptron_count, double* weights=0)
		: m_rActiveRate(active_rate), m_nActiveMode(active_mode), m_nXSize(input_size), m_nOSize(output_size)
		, m_nPerceptronCount(perceptron_count), m_bIsShell(false)
	{
		m_pX=new double[m_nXSize];
		m_pO=new double[m_nOSize];
		m_pPerceptrons=new Perceptron[m_nPerceptronCount];

		m_nWeightCount=(m_pPerceptrons[0].nInputCount=m_nXSize)+1;
		for(int i=1;i<m_nPerceptronCount;i++)
		{
			m_pPerceptrons[i].nInputCount=m_nXSize+i;
			m_nWeightCount+=m_pPerceptrons[i].nInputCount+1;
		}
		m_pWeights=new double[m_nWeightCount];

		double* p_weights=m_pWeights;
		for(int i=0;i<m_nPerceptronCount;i++)
		{
			m_pPerceptrons[i].pWeights=p_weights;
			p_weights+=m_pPerceptrons[i].nInputCount+1;
		}

		if(weights)
		{
			memcpy(m_pWeights,weights,sizeof(double)*m_nWeightCount);
		}
		else
		{
			for(int i=0;i<m_nPerceptronCount;i++)
			{
				for(int j=0;j<m_pPerceptrons[i].nInputCount;j++)
					m_pPerceptrons[i].pWeights[j]=randR(0.5,-0.5);
				m_pPerceptrons[i].pWeights[ m_pPerceptrons[i].nInputCount]=randR(0.05,-0.05);
			}
		}
	}
	MSP(MSP& msp)
		:m_rActiveRate(msp.m_rActiveRate), m_nActiveMode(msp.m_nActiveMode), m_nXSize(msp.m_nXSize)
		, m_nOSize(msp.m_nOSize), m_nPerceptronCount(msp.m_nPerceptronCount), m_bIsShell(true)
		, m_nWeightCount(msp.m_nWeightCount)
	{
		m_pX=new double[m_nXSize];
		m_pO=new double[m_nOSize];
		m_pPerceptrons=new Perceptron[m_nPerceptronCount];

		for(int i=0;i<m_nPerceptronCount;i++)
			m_pPerceptrons[i].nInputCount=msp.m_pPerceptrons[i].nInputCount;

		m_pWeights=msp.m_pWeights;

		double* p_weights=m_pWeights;
		for(int i=0;i<m_nPerceptronCount;i++)
		{
			m_pPerceptrons[i].pWeights=p_weights;
			p_weights+=m_pPerceptrons[i].nInputCount+1;
		}
	}
	~MSP(void)
	{
		delete[] m_pX;
		delete[] m_pO;
		delete[] m_pPerceptrons;
		if(!m_bIsShell)
			delete[] m_pWeights;
	};

	double Activate(double sum)
	{
		if(m_nActiveMode)
			return 2.0/(1+exp(-m_rActiveRate*sum))-1;
		else
			return 1.0/(1+exp(-m_rActiveRate*sum));
	}

	void Stimulate(double* x)
	{
		memcpy(m_pX,x,sizeof(double)*m_nXSize);

		for(int i=0;i<m_nPerceptronCount;i++)
		{
			double sum=0;
			for(int j=0;j<m_pPerceptrons[i].nInputCount;j++)
			{
				if(j<m_nXSize)
					sum+=m_pX[j]*m_pPerceptrons[i].pWeights[j];
				else
					sum+=m_pPerceptrons[j-m_nXSize].rO*m_pPerceptrons[i].pWeights[j];
			}
			sum+=m_pPerceptrons[i].pWeights[m_pPerceptrons[i].nInputCount];
			if(i>=m_nPerceptronCount-m_nOSize)
				m_pO[i-(m_nPerceptronCount-m_nOSize)]=m_pPerceptrons[i].rO=Activate(sum);
			else
				m_pPerceptrons[i].rO=Activate(sum);
		}
	}
};

